home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / WINGs / userdefaults.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-23  |  13.5 KB  |  654 lines

  1.  
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdio.h>
  5. #include <assert.h>
  6. #include <unistd.h>
  7. #include <sys/stat.h>
  8.  
  9.  
  10. #include "../src/config.h"
  11.  
  12. #include "WINGs.h"
  13.  
  14. #include <proplist.h>
  15.  
  16.  
  17. typedef struct W_UserDefaults {
  18.     proplist_t defaults;
  19.  
  20.     proplist_t appDomain;
  21.  
  22.     proplist_t searchListArray;
  23.     proplist_t *searchList;           /* cache for searchListArray */
  24.  
  25.     char dirty;
  26.  
  27.     char dontSync;
  28.  
  29.     char *path;                        /* where is db located */
  30.  
  31.     time_t timestamp;                  /* last modification time */
  32.  
  33.     struct W_UserDefaults *next;
  34.  
  35. } UserDefaults;
  36.  
  37.  
  38. static UserDefaults *sharedUserDefaults = NULL;
  39.  
  40. char *WMUserDefaultsDidChangeNotification = "WMUserDefaultsDidChangeNotification";
  41.  
  42.  
  43.  
  44. extern char *WMGetApplicationName();
  45.  
  46. #define DEFAULTS_DIR "/Defaults"
  47.  
  48. #define UD_SYNC_INTERVAL  2000
  49.  
  50.  
  51.  
  52. char*
  53. wusergnusteppath()
  54. {
  55.     static char *path = NULL;
  56.     char *gspath;
  57.     int pathlen;
  58.  
  59.     if (!path) {
  60.     gspath = getenv("GNUSTEP_USER_ROOT");
  61.     if (gspath) {
  62.         gspath = wexpandpath(gspath);
  63.         pathlen = strlen(gspath) + 4;
  64.         path = wmalloc(pathlen);
  65.         strcpy(path, gspath);
  66.         wfree(gspath);
  67.     } else {
  68.         pathlen = strlen(wgethomedir()) + 10;
  69.         path = wmalloc(pathlen);
  70.         strcpy(path, wgethomedir());
  71.         strcat(path, "/GNUstep");
  72.     }
  73.     }
  74.  
  75.     return path;
  76. }
  77.  
  78.  
  79. char*
  80. wdefaultspathfordomain(char *domain)
  81. {
  82.     char *path;
  83.     char *gspath;
  84.  
  85.     gspath = wusergnusteppath();
  86.     path = wmalloc(strlen(gspath)+strlen(DEFAULTS_DIR)+strlen(domain)+4);
  87.     strcpy(path, gspath);
  88.     strcat(path, DEFAULTS_DIR);
  89.     strcat(path, "/");
  90.     strcat(path, domain);
  91.  
  92.     return path;
  93. }
  94.  
  95.  
  96. static void
  97. #ifndef HAVE_ATEXIT
  98. saveDefaultsChanges(int foo, void *bar)
  99. #else
  100. saveDefaultsChanges(void)
  101. #endif
  102. {
  103.     /* save the user defaults databases */
  104.     UserDefaults *tmp = sharedUserDefaults;
  105.  
  106.     while (tmp) {
  107.         WMSynchronizeUserDefaults(tmp);
  108.         tmp = tmp->next;
  109.     }
  110. }
  111.  
  112.  
  113. /* set to save changes in defaults when program is exited */
  114. static void
  115. registerSaveOnExit(void)
  116. {
  117.     static Bool registeredSaveOnExit = False;
  118.  
  119.     if (!registeredSaveOnExit) {
  120. #ifndef HAVE_ATEXIT
  121.         on_exit(saveDefaultsChanges, (void*)NULL);
  122. #else
  123.         atexit(saveDefaultsChanges);
  124. #endif
  125.         registeredSaveOnExit = True;
  126.     }
  127. }
  128.  
  129.  
  130. static void
  131. synchronizeUserDefaults(void *foo)
  132. {
  133.     UserDefaults *database = sharedUserDefaults;
  134.  
  135.     while (database) {
  136.         if (!database->dontSync)
  137.             WMSynchronizeUserDefaults(database);
  138.         database = database->next;
  139.     }
  140.     WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
  141. }
  142.  
  143.  
  144. static void
  145. addSynchronizeTimerHandler(void)
  146. {
  147.     static Bool initialized = False;
  148.  
  149.     if (!initialized) {
  150.         WMAddTimerHandler(UD_SYNC_INTERVAL, synchronizeUserDefaults, NULL);
  151.         initialized = True;
  152.     }
  153. }
  154.  
  155.  
  156. void
  157. WMEnableUDPeriodicSynchronization(WMUserDefaults *database, Bool enable)
  158. {
  159.     database->dontSync = !enable;
  160. }
  161.  
  162.  
  163. void
  164. WMSynchronizeUserDefaults(WMUserDefaults *database)
  165. {
  166.     Bool fileIsNewer = False, release = False;
  167.     char *path;
  168.     struct stat stbuf;
  169.  
  170.     if (!database->path) {
  171.         path = wdefaultspathfordomain(WMGetApplicationName());
  172.         release = True;
  173.     } else {
  174.         path = database->path;
  175.     }
  176.  
  177.     if (stat(path, &stbuf) >= 0 && stbuf.st_mtime > database->timestamp)
  178.         fileIsNewer = True;
  179.  
  180.     if (database->appDomain && (database->dirty || fileIsNewer)) {
  181.  
  182.         /*fprintf(stderr, "syncing: %s %d %d\n", path, database->dirty, fileIsNewer);*/
  183.  
  184.         PLShallowSynchronize(database->appDomain);
  185.         database->dirty = 0;
  186.         if (stat(path, &stbuf) >= 0)
  187.             database->timestamp = stbuf.st_mtime;
  188.         if (fileIsNewer) {
  189.             WMPostNotificationName(WMUserDefaultsDidChangeNotification,
  190.                                    database, NULL);
  191.         }
  192.     }
  193.  
  194.     if (release)
  195.         wfree(path);
  196.  
  197. }
  198.  
  199.  
  200. void
  201. WMSaveUserDefaults(WMUserDefaults *database)
  202. {
  203.     if (database->appDomain) {
  204.         struct stat stbuf;
  205.         char *path;
  206.         Bool release = False;
  207.  
  208.         PLSave(database->appDomain, YES);
  209.         database->dirty = 0;
  210.         if (!database->path) {
  211.             path = wdefaultspathfordomain(WMGetApplicationName());
  212.             release = True;
  213.         } else {
  214.             path = database->path;
  215.         }
  216.         if (stat(path, &stbuf) >= 0)
  217.             database->timestamp = stbuf.st_mtime;
  218.         if (release)
  219.             wfree(path);
  220.     }
  221. }
  222.  
  223.  
  224. WMUserDefaults*
  225. WMGetStandardUserDefaults(void)
  226. {
  227.     WMUserDefaults *defaults;
  228.     proplist_t domain;
  229.     proplist_t key;
  230.     struct stat stbuf;
  231.     char *path;
  232.     int i;
  233.  
  234.     if (sharedUserDefaults) {
  235.         defaults = sharedUserDefaults;
  236.         while (defaults) {
  237.             /* Trick, path == NULL only for StandardUserDefaults db */
  238.             if (defaults->path == NULL)
  239.                 return defaults;
  240.             defaults = defaults->next;
  241.         }
  242.     }
  243.  
  244.     /* we didn't found the database we are looking for. Go read it. */
  245.     defaults = wmalloc(sizeof(WMUserDefaults));
  246.     memset(defaults, 0, sizeof(WMUserDefaults));
  247.  
  248.     defaults->defaults = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
  249.  
  250.     defaults->searchList = wmalloc(sizeof(proplist_t)*3);
  251.  
  252.     /* application domain */
  253.     key = PLMakeString(WMGetApplicationName());
  254.     defaults->searchList[0] = key;
  255.  
  256.     /* temporary kluge */
  257.     if (strcmp(WMGetApplicationName(), "WindowMaker")==0) {
  258.         domain = NULL;
  259.         path = NULL;
  260.     } else {
  261.         path = wdefaultspathfordomain(PLGetString(key));
  262.  
  263.         if (stat(path, &stbuf) >= 0)
  264.             defaults->timestamp = stbuf.st_mtime;
  265.  
  266.         domain = PLGetProplistWithPath(path);
  267.     }
  268.     if (!domain) {
  269.         proplist_t p;
  270.  
  271.         domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
  272.         if (path) {
  273.             p = PLMakeString(path);
  274.             PLSetFilename(domain, p);
  275.             PLRelease(p);
  276.         }
  277.     }
  278.     if (path)
  279.         wfree(path);
  280.  
  281.     defaults->appDomain = domain;
  282.  
  283.     if (domain)
  284.         PLInsertDictionaryEntry(defaults->defaults, key, domain);
  285.  
  286.     PLRelease(key);
  287.  
  288.     /* global domain */
  289.     key = PLMakeString("WMGLOBAL");
  290.     defaults->searchList[1] = key;
  291.  
  292.     path = wdefaultspathfordomain(PLGetString(key));
  293.  
  294.     domain = PLGetProplistWithPath(path);
  295.  
  296.     wfree(path);
  297.  
  298.     if (!domain)
  299.         domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
  300.  
  301.     if (domain)
  302.         PLInsertDictionaryEntry(defaults->defaults, key, domain);
  303.  
  304.     PLRelease(key);
  305.  
  306.     /* terminate list */
  307.     defaults->searchList[2] = NULL;
  308.  
  309.     defaults->searchListArray = PLMakeArrayFromElements(NULL,NULL);
  310.  
  311.     i = 0;
  312.     while (defaults->searchList[i]) {
  313.         PLAppendArrayElement(defaults->searchListArray,
  314.                              defaults->searchList[i]);
  315.         i++;
  316.     }
  317.  
  318.     if (sharedUserDefaults)
  319.         defaults->next = sharedUserDefaults;
  320.     sharedUserDefaults = defaults;
  321.  
  322.     addSynchronizeTimerHandler();
  323.     registerSaveOnExit();
  324.  
  325.     return defaults;
  326. }
  327.  
  328.  
  329. WMUserDefaults*
  330. WMGetDefaultsFromPath(char *path)
  331. {
  332.     WMUserDefaults *defaults;
  333.     proplist_t domain;
  334.     proplist_t key;
  335.     struct stat stbuf;
  336.     char *name;
  337.     int i;
  338.  
  339.     assert(path != NULL);
  340.  
  341.     if (sharedUserDefaults) {
  342.         defaults = sharedUserDefaults;
  343.         while (defaults) {
  344.             if (defaults->path && strcmp(defaults->path, path) == 0)
  345.                 return defaults;
  346.             defaults = defaults->next;
  347.         }
  348.     }
  349.  
  350.     /* we didn't found the database we are looking for. Go read it. */
  351.     defaults = wmalloc(sizeof(WMUserDefaults));
  352.     memset(defaults, 0, sizeof(WMUserDefaults));
  353.  
  354.     defaults->defaults = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
  355.  
  356.     defaults->searchList = wmalloc(sizeof(proplist_t)*2);
  357.  
  358.     /* the domain we want, go in the first position */
  359.     name = strrchr(path, '/');
  360.     if (!name)
  361.         name = path;
  362.     else
  363.         name++;
  364.  
  365.     key = PLMakeString(name);
  366.     defaults->searchList[0] = key;
  367.  
  368.     if (stat(path, &stbuf) >= 0)
  369.         defaults->timestamp = stbuf.st_mtime;
  370.  
  371.     domain = PLGetProplistWithPath(path);
  372.  
  373.     if (!domain) {
  374.         proplist_t p;
  375.  
  376.         domain = PLMakeDictionaryFromEntries(NULL, NULL, NULL);
  377.         p = PLMakeString(path);
  378.         PLSetFilename(domain, p);
  379.         PLRelease(p);
  380.     }
  381.  
  382.     defaults->path = wstrdup(path);
  383.  
  384.     defaults->appDomain = domain;
  385.  
  386.     if (domain)
  387.         PLInsertDictionaryEntry(defaults->defaults, key, domain);
  388.  
  389.     PLRelease(key);
  390.  
  391.     /* terminate list */
  392.     defaults->searchList[1] = NULL;
  393.  
  394.     defaults->searchListArray = PLMakeArrayFromElements(NULL,NULL);
  395.  
  396.     i = 0;
  397.     while (defaults->searchList[i]) {
  398.         PLAppendArrayElement(defaults->searchListArray,
  399.                              defaults->searchList[i]);
  400.         i++;
  401.     }
  402.  
  403.     if (sharedUserDefaults)
  404.         defaults->next = sharedUserDefaults;
  405.     sharedUserDefaults = defaults;
  406.  
  407.     addSynchronizeTimerHandler();
  408.     registerSaveOnExit();
  409.  
  410.     return defaults;
  411. }
  412.  
  413.  
  414. proplist_t
  415. WMGetUDObjectForKey(WMUserDefaults *database, char *defaultName)
  416. {
  417.     proplist_t domainName, domain;
  418.     proplist_t object = NULL;
  419.     proplist_t key = PLMakeString(defaultName);
  420.     int i = 0;
  421.     
  422.     while (database->searchList[i] && !object) {
  423.     domainName = database->searchList[i];
  424.     domain = PLGetDictionaryEntry(database->defaults, domainName);
  425.     if (domain) {
  426.         object = PLGetDictionaryEntry(domain, key);
  427.     }
  428.     i++;
  429.     }
  430.     PLRelease(key);
  431.     
  432.     return object;
  433. }
  434.  
  435.  
  436. void
  437. WMSetUDObjectForKey(WMUserDefaults *database, proplist_t object,
  438.             char *defaultName)
  439. {
  440.     proplist_t key = PLMakeString(defaultName);
  441.  
  442.     database->dirty = 1;
  443.  
  444.     PLInsertDictionaryEntry(database->appDomain, key, object);
  445.     PLRelease(key);
  446. }
  447.  
  448.  
  449. void
  450. WMRemoveUDObjectForKey(WMUserDefaults *database, char *defaultName)
  451. {
  452.     proplist_t key = PLMakeString(defaultName);
  453.  
  454.     database->dirty = 1;
  455.  
  456.     PLRemoveDictionaryEntry(database->appDomain, key);
  457.     
  458.     PLRelease(key);
  459. }
  460.  
  461.  
  462. char*
  463. WMGetUDStringForKey(WMUserDefaults *database, char *defaultName)
  464. {
  465.     proplist_t val;
  466.     
  467.     val = WMGetUDObjectForKey(database, defaultName);
  468.  
  469.     if (!val)
  470.     return NULL;
  471.  
  472.     if (!PLIsString(val))
  473.     return NULL;
  474.  
  475.     return PLGetString(val);
  476. }
  477.  
  478.  
  479. int
  480. WMGetUDIntegerForKey(WMUserDefaults *database, char *defaultName)
  481. {
  482.     proplist_t val;
  483.     char *str;
  484.     int value;
  485.  
  486.     val = WMGetUDObjectForKey(database, defaultName);
  487.     
  488.     if (!val)
  489.     return 0;
  490.  
  491.     if (!PLIsString(val))
  492.     return 0;
  493.     
  494.     str = PLGetString(val);
  495.     if (!str)
  496.     return 0;
  497.     
  498.     if (sscanf(str, "%i", &value)!=1)
  499.     return 0;
  500.  
  501.     return value;
  502. }
  503.  
  504.  
  505.  
  506. float
  507. WMGetUDFloatForKey(WMUserDefaults *database, char *defaultName)
  508. {
  509.     proplist_t val;
  510.     char *str;
  511.     float value;
  512.  
  513.     val = WMGetUDObjectForKey(database, defaultName);
  514.     
  515.     if (!val || !PLIsString(val))
  516.     return 0.0;
  517.  
  518.     if (!(str = PLGetString(val)))
  519.     return 0.0;
  520.  
  521.     if (sscanf(str, "%f", &value)!=1)
  522.     return 0.0;
  523.  
  524.     return value;
  525. }
  526.  
  527.  
  528.  
  529. Bool
  530. WMGetUDBoolForKey(WMUserDefaults *database, char *defaultName)
  531. {
  532.     proplist_t val;
  533.     int value;
  534.     char *str;
  535.  
  536.     val = WMGetUDObjectForKey(database, defaultName);
  537.     
  538.     if (!val)
  539.     return False;
  540.  
  541.     if (!PLIsString(val))
  542.     return False;
  543.     
  544.     str = PLGetString(val);
  545.     if (!str)
  546.     return False;
  547.     
  548.     if (sscanf(str, "%i", &value)==1 && value!=0)
  549.     return True;
  550.  
  551.     if (strcasecmp(str, "YES")==0)
  552.     return True;
  553.  
  554.     if (strcasecmp(str, "Y")==0)
  555.     return True;
  556.  
  557.     return False;
  558. }
  559.  
  560.  
  561. void
  562. WMSetUDIntegerForKey(WMUserDefaults *database, int value, char *defaultName)
  563. {
  564.     proplist_t object;
  565.     char buffer[128];
  566.  
  567.     sprintf(buffer, "%i", value);
  568.     object = PLMakeString(buffer);
  569.  
  570.     WMSetUDObjectForKey(database, object, defaultName);
  571.     PLRelease(object);
  572. }
  573.  
  574.  
  575.  
  576.  
  577. void
  578. WMSetUDStringForKey(WMUserDefaults *database, char *value, char *defaultName)
  579. {
  580.     proplist_t object;
  581.  
  582.     object = PLMakeString(value);
  583.  
  584.     WMSetUDObjectForKey(database, object, defaultName);
  585.     PLRelease(object);
  586. }
  587.  
  588.  
  589.  
  590. void
  591. WMSetUDFloatForKey(WMUserDefaults *database, float value, char *defaultName)
  592. {
  593.     proplist_t object;
  594.     char buffer[128];
  595.  
  596.     sprintf(buffer, "%f", value);
  597.     object = PLMakeString(buffer);
  598.  
  599.     WMSetUDObjectForKey(database, object, defaultName);
  600.     PLRelease(object);
  601. }
  602.  
  603.  
  604.  
  605. void
  606. WMSetUDBoolForKey(WMUserDefaults *database, Bool value, char *defaultName)
  607. {
  608.     static proplist_t yes = NULL, no = NULL;
  609.  
  610.     if (!yes) {
  611.     yes = PLMakeString("YES");
  612.     no = PLMakeString("NO");
  613.     }
  614.  
  615.     WMSetUDObjectForKey(database, value ? yes : no, defaultName);
  616. }
  617.  
  618.  
  619. proplist_t
  620. WMGetUDSearchList(WMUserDefaults *database)
  621. {
  622.     return database->searchListArray;
  623. }
  624.  
  625.  
  626. void
  627. WMSetUDSearchList(WMUserDefaults *database, proplist_t list)
  628. {
  629.     int i, c;
  630.     
  631.     if (database->searchList) {
  632.     i = 0;
  633.     while (database->searchList[i]) {
  634.         PLRelease(database->searchList[i]);
  635.         i++;
  636.     }
  637.     wfree(database->searchList);
  638.     }
  639.     if (database->searchListArray) {
  640.     PLRelease(database->searchListArray);
  641.     }
  642.  
  643.     c = PLGetNumberOfElements(list);
  644.     database->searchList = wmalloc(sizeof(proplist_t)*(c+1));
  645.  
  646.     for (i=0; i<c; i++) {
  647.     database->searchList[i] = PLGetArrayElement(list, i);
  648.     }
  649.     
  650.     database->searchListArray = PLDeepCopy(list);
  651. }
  652.  
  653.  
  654.